package com.neuedu.wemall.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.neuedu.wemall.common.util.MD5;
import com.neuedu.wemall.common.util.RandomCodeUtils;
import com.neuedu.wemall.common.util.RedisUtils;
import com.neuedu.wemall.common.util.SHAEncryptUtils;
import com.neuedu.wemall.common.util.mail.EmailService;
import com.neuedu.wemall.common.vo.ResponseData;
import com.neuedu.wemall.dao.entity.Member;
import com.neuedu.wemall.dao.mapper.MemberMapper;
import com.neuedu.wemall.service.IMemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

@Service("memberService")
public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> implements IMemberService {
    /**
     * 注册邮箱验证码key前缀
     */
    private final String REG_CODE_KEY_PREFIX = "register:email:code:";
    /**
     * 找回密码邮箱验证码key前缀
     */
    private final String FIND_PWD_CODE_KEY_PREFIX = "find:password:email:code:";

    @Autowired
    private RedisUtils redisUtils;

    @Override
    public ResponseData sendRegisterCode(String email) {
        //判断邮箱是否为空
        if (StrUtil.isEmpty(email)) {
            return ResponseData.fail(999, "邮箱不能为空");
        }
        //判断邮箱格式
        if (!validateEmail(email)) {
            return ResponseData.fail(999, "邮箱格式错误");
        }
        //判断当前邮箱是否已被注册
        QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
        //tom@163.com TOM@163.com  Tom@163.com
        queryWrapper.eq("LOWER(email)", email.toLowerCase());
        int count = getBaseMapper().selectCount(queryWrapper).intValue();
        if (count > 0) {
            return ResponseData.fail(999, "该邮箱已被注册");
        }
        //生成随机验证码
        String mailCode = RandomCodeUtils.bulidNoRepeatCodes(6);
        //发送验证码
        try {
            EmailService.sentMailHtml("会员注册", "欢迎注册东软微商城会员,您当前的验证码为:<span style='color:blue;font-weight:800;font-size:20px;'>" + mailCode + "</span>", email);
            //将邮件验证码保存包redis中
            String key = REG_CODE_KEY_PREFIX + email;
            redisUtils.set(key, mailCode, 180);
            return ResponseData.success("success");
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseData.fail(999, "服务器异常,验证码发送失败");
        }
    }

    public ResponseData sendFindPasswordCode(String email) {
        //判断邮箱是否为空
        if (StrUtil.isEmpty(email)) {
            return ResponseData.fail(999, "邮箱不能为空");
        }
        //判断邮箱格式
        if (!validateEmail(email)) {
            return ResponseData.fail(999, "邮箱格式错误");
        }
        //判断当前邮箱是否已被注册
        QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
        //tom@163.com TOM@163.com  Tom@163.com
        queryWrapper.eq("LOWER(email)", email.toLowerCase());
        int count = getBaseMapper().selectCount(queryWrapper).intValue();
        if (count == 0) {
            return ResponseData.fail(999, "该邮箱未被注册");
        }
        //生成随机验证码
        String mailCode = RandomCodeUtils.bulidNoRepeatCodes(6);
        //发送验证码
        try {
            EmailService.sentMailHtml("忘记密码", "亲爱的东软微商城会员,您正在找回密码,当前的验证码为:<span style='color:blue;font-weight:800;font-size:20px;'>" + mailCode + "</span>", email);
            //将邮件验证码保存包redis中
            String key = FIND_PWD_CODE_KEY_PREFIX + email;
            redisUtils.set(key, mailCode, 180);
            return ResponseData.success("success");
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseData.fail(999, "服务器异常,验证码发送失败");
        }
    }

    /**
     * 验证电子邮箱格式是否合法
     *
     * @param email 待验证的邮箱地址
     * @return true-格式合法，false-格式不合法
     */
    private boolean validateEmail(String email) {
        if (StrUtil.isEmpty(email)) {
            return false;
        }
        // 邮箱格式正则表达式（保持原校验规则不变）
        String emailRegex = "^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[a-zA-Z0-9]{2,6}$";
        return email.matches(emailRegex);
    }

    @Override
    public ResponseData register(String email, String emailCode, String password) {
        if (!validateEmail(email)) {
            return ResponseData.fail(999, "邮箱格式错误");
        }
        //判断当前邮箱是否已被注册
        QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
        //tom@163.com TOM@163.com  Tom@163.com
        queryWrapper.eq("LOWER(email)", email.toLowerCase());
        int count = getBaseMapper().selectCount(queryWrapper).intValue();
        if (count > 0) {
            return ResponseData.fail(999, "该邮箱已被注册");
        }
        String key = REG_CODE_KEY_PREFIX + email;
        String redisCode = (String) redisUtils.get(key);
        if (redisCode == null) {
            return ResponseData.fail(999, "邮件验证码已过期");
        }
        if (!redisCode.equalsIgnoreCase(emailCode)) {
            return ResponseData.fail(999, "验证码错误");
        }
        //验证密码的格式
        if (!validatePassword(password)) {
            return ResponseData.fail(999, "密码格式错误");
        }
        //生成随机盐
        String salt = RandomCodeUtils.bulidRepeatCodes(64);
        //密码加密
        password = encryptPassword(password, salt);
        Member member = new Member();
        member.setEmail(email);
        member.setPassword(password);
        //昵称默认与邮箱相同
        member.setNickname(email);
        member.setStatus(1);
        member.setLevel(1);
        member.setRegChannel("WEB");
        member.setSalt(salt);//设置该会员用户加密盐
        member.setRegTime(new Date());//注册时间默认服务器时间
        int rows = getBaseMapper().insert(member);
        return ResponseData.success(rows);
    }

    @Override
    public ResponseData resetPassword(String email, String emailCode, String password) {
        if (!validateEmail(email)) {
            return ResponseData.fail(999, "邮箱格式错误");
        }
        Member member = getMemberByEmail(email);
        if (member == null) {
            return ResponseData.fail(999, "该邮箱未注册");
        }
        String key = FIND_PWD_CODE_KEY_PREFIX + email;
        String redisCode = (String) redisUtils.get(key);
        if (redisCode == null) {
            return ResponseData.fail(999, "邮件验证码已过期");
        }
        if (!redisCode.equalsIgnoreCase(emailCode)) {
            return ResponseData.fail(999, "验证码错误");
        }
        //验证密码的格式
        if (!validatePassword(password)) {
            return ResponseData.fail(999, "密码格式错误");
        }
        //密码加密
        String salt = member.getSalt();
        password = encryptPassword(password, salt);
        LambdaUpdateWrapper<Member> luw = new LambdaUpdateWrapper<>();
        luw.eq(Member::getId, member.getId());
        luw.set(Member::getPassword, password);
        int rows = getBaseMapper().update(luw);
        return ResponseData.success(rows);
    }

    @Override
    public ResponseData updatePassword(int userId, String oldPwd, String newPwd, String confirmPwd) {
        //判断旧密码是否正确
        Member member = getById(userId);
        if (member == null) {
            return ResponseData.fail(999, "用户不存在");
        }
        String oldPwdDB = member.getPassword();
        String salt = member.getSalt();
        String password = encryptPassword(oldPwd, salt);
        if (!password.equals(oldPwdDB)) {
            return ResponseData.fail(999, "旧密码错误");
        }
        if (oldPwd.equals(newPwd)) {
            return ResponseData.fail(999, "新密码不能与旧密码相同");
        }
        if (!newPwd.equals(confirmPwd)) {
            return ResponseData.fail(999, "新密码与确认密码不一致");
        }
        if (!validatePassword(newPwd)) {
            return ResponseData.fail(999, "新密码格式错误");
        }
        newPwd = encryptPassword(newPwd, salt);//将新密码加密
        //修改
        LambdaUpdateWrapper<Member> luw = new LambdaUpdateWrapper<>();
        luw.eq(Member::getId, userId);
        luw.set(Member::getPassword, newPwd);
        int rows = getBaseMapper().update(luw);
        return ResponseData.success(rows);
    }

    @Override
    public Member login(String email, String password) {
        Member member = getMemberByEmail(email);
        if (member == null) {
            return null;
        }
        String salt = member.getSalt();
        //密码加密
        password = encryptPassword(password, salt);
        //表中的密码(真实密码)
        String realPwd = member.getPassword();
        return password.equals(realPwd) ? member : null;
    }

    /**
     * 根据邮箱查询用户
     *
     * @param email
     * @return
     */
    private Member getMemberByEmail(String email) {
        LambdaQueryWrapper<Member> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Member::getEmail, email.toLowerCase());
        List<Member> list = getBaseMapper().selectList(lqw);
        if (CollectionUtil.isEmpty(list)) {
            return null;
        }
        int len = list.size();
        if (len > 1) {
            throw new IllegalArgumentException("数据异常,请联系客户人员");
        }
        Member member = list.get(0);
        String salt = member.getSalt();
        if (StrUtil.isEmpty(salt) || 64 != salt.length()) {
            throw new IllegalArgumentException("数据异常,请联系客户人员");
        }
        return member;
    }

    /**
     * 密码加密
     *
     * @param password 密码
     * @param salt     盐
     * @return 加密后的密码
     */
    private static String encryptPassword(String password, String salt) {
        String url = "https://www.wemall.com/?salt={}&i={}&password={}";
        url = StrUtil.format(url, salt);
        for (int i = 1; i <= 150; i++) {
            String content = new String(url);
            content = StrUtil.format(content, i, password);
            password = SHAEncryptUtils.getSHA512(content);
        }
        for (int i = 1; i <= 150; i++) {
            String content = new String(url);
            content = StrUtil.format(content, i, password);
            password = MD5.getMD5(content);
        }
        return password;
    }

    /**
     * 使用正则表达式验证密码，密码由大小写字母、数字、标点符号组成，长度范围为 8 - 20，
     * 必须包含数字、大写字母、小写字母、标点符号其中三种，不能含有空白字符和转义字符
     *
     * @param password 待验证的密码
     * @return 若密码符合规则返回 true，否则返回 false
     */
    private static boolean validatePassword(String password) {
        if (password == null || password.length() < 8 || password.length() > 20) {
            return false;
        }

        // 检查是否包含空白字符或转义字符
        if (password.matches(".*[\\s\\\\].*")) {
            System.out.println(11);
            return false;
        }

        // 定义不同字符类型的正则表达式
        int criteriaMet = 0;
        if (password.matches(".*[0-9].*")) { // 数字
            criteriaMet++;
        }
        if (password.matches(".*[A-Z].*")) { // 大写字母
            criteriaMet++;
        }
        if (password.matches(".*[a-z].*")) { // 小写字母
            criteriaMet++;
        }
        if (password.matches(".*[^a-zA-Z0-9\\s].*")) { // 标点符号
            criteriaMet++;
        }
        // 必须满足至少三种条件
        return criteriaMet >= 3;
    }

    @Override
    public ResponseData modifyById(Member member) {
        Integer userId = member.getId();
        if (userId == null) {
            return ResponseData.modifyFail("缺少会员ID");
        }
        boolean updated = false;
        Member dbMember = getBaseMapper().selectById(userId);
        if (dbMember == null) {
            return ResponseData.modifyFail("会员不存在");
        }
        LambdaUpdateWrapper<Member> luw = new LambdaUpdateWrapper<>();
        luw.eq(Member::getId, userId);
        String username = member.getUsername();
        if (StrUtil.isNotEmpty(username)) {
            if (containsUKVal(userId, username)) {
                return ResponseData.modifyFail("用户名已存在");
            }
            updated = true;
            luw.set(Member::getUsername, username);
        }
        String mobile = member.getMobile();
        if (StrUtil.isNotEmpty(mobile)) {
            if (containsUKVal(userId, mobile)) {
                return ResponseData.modifyFail("手机号已存在");
            }
            updated = true;
            luw.set(Member::getMobile, mobile);
        }
        Integer gender = member.getGender();
        if (!(gender == null || gender == 1 || 2 == gender)) {
            return ResponseData.modifyFail("性别状态错误");
        }
        if (gender != null) {
            updated = true;
            luw.set(Member::getGender, gender);
        }
        String nickname = member.getNickname();
        if (StrUtil.isNotEmpty(nickname)) {
            updated = true;
            luw.set(Member::getNickname, nickname);
        }
        String city = member.getCity();
        if (StrUtil.isNotEmpty(city)) {
            updated = true;
            luw.set(Member::getCity, city);
        }
        String idCard = member.getIdCard();
        if (StrUtil.isNotEmpty(idCard)) {
            if (containsUKVal(userId, idCard)) {
                return ResponseData.modifyFail("身份证号已存在");
            }
            updated = true;
            luw.set(Member::getIdCard, idCard);
        }
        String avatar = member.getAvatar();
        if (StrUtil.isNotEmpty(avatar)) {
            updated = true;
            luw.set(Member::getAvatar, avatar);
        }
        Date birth = member.getBirth();
        if (birth != null) {
            updated = true;
            luw.set(Member::getBirth, birth);
        }
        if (!updated) {
            return ResponseData.modifyFail("当前没有更新任何数据");
        }
        int rows = getBaseMapper().update(member, luw);
        return ResponseData.success(rows);
    }

    /**
     * 统计查询唯一字段值数量
     *
     * @param userId   用户ID
     * @param fieldVal 唯一字段
     * @return
     */
    private boolean containsUKVal(Integer userId, String fieldVal) {
        LambdaQueryWrapper<Member> lqw = new LambdaQueryWrapper<>();
        if (StrUtil.isEmpty(fieldVal)) {
            throw new IllegalArgumentException("检查唯一字段值是否重复,字段值不能为空");
        }
        lqw.and(swq -> {
            swq.eq(Member::getMobile, fieldVal);
            swq.or();
            swq.eq(Member::getUsername, fieldVal);
            swq.or();
            swq.eq(Member::getIdCard, fieldVal);
        });
        if (userId != null) {
            lqw.ne(Member::getId, userId);
        }
        int count = getBaseMapper().selectCount(lqw).intValue();
        if (count > 1) {
            throw new IllegalArgumentException("检查唯一字段值是否重复,数据异常");
        }
        return 1 == count;
    }
}